package edu.pku.sei.scriptengine.test;

import java.util.ArrayList;

import junit.framework.TestCase;
import edu.pku.sei.mdabase.basictypes.CollectionType;
import edu.pku.sei.mdabase.basictypes.OCLInvalid;
import edu.pku.sei.mdabase.basictypes.OCLVoidValue;
import edu.pku.sei.mdabase.basictypes.PrimitiveType;
import edu.pku.sei.mdabase.infrastructure.metamodel.MetaClass;
import edu.pku.sei.mdabase.infrastructure.model.MClass;
import edu.pku.sei.mdabase.infrastructure.runtime.Context;
import edu.pku.sei.mdabase.infrastructure.runtime.Variable;
import edu.pku.sei.queryscript.parser.QueryScriptLexer;
import edu.pku.sei.queryscript.parser.QueryScriptParser;
import edu.pku.sei.queryscript.parser.ScriptParser;
import edu.pku.sei.queryscript.parser.Ast.Ast;
import edu.pku.sei.scriptengine.visitor.ExpressionCheckVisitor;
import edu.pku.sei.scriptengine.visitor.ExpressionEnforceVisitor;
import edu.pku.sei.scriptengine.visitor.ModelCheckVisitor;
import edu.pku.sei.scriptengine.visitor.QueryVisitor;

public class CheckOnlyTestCase extends TestCase {
	
	public void testAttribute() {
	
		MetaClass metaClass = new MetaClass();
		metaClass.setName("T");
		metaClass.addAttribute("value", PrimitiveType.TYPE_INTEGER, 0);
		MClass c = new MClass();
		c.setType(metaClass);
		c.getAttribute("value").setValue(1);
		
		Variable mv = new Variable();
		mv.setName("c");
		mv.setValue(c);
		mv.setType(metaClass);
		
		
		Context context = new Context();
		context.registVariable("c", null, true).setValue(mv);
		QueryVisitor visitor = new ExpressionCheckVisitor(context);
		Ast ast;
		String s;
		Object obj;
		s="c.value=1;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue((Boolean)obj);
	}
	public void testLargerLess() {
		Context context = new Context();
		context.registVariable("a", PrimitiveType.TYPE_INTEGER, false).setValue(new Integer(2));
		context.registVariable("b", PrimitiveType.TYPE_STRING, false).setValue("abc");
		context.registVariable("c", PrimitiveType.TYPE_BOOLEAN, false).setValue(new Boolean(false));
		QueryVisitor visitor = new ModelCheckVisitor(context);
		Ast ast;
		String s;
		Object obj;
		
		s="1>2;";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertFalse((Boolean)obj);
		
		s="1<a;";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue((Boolean)obj);
		
		s="true>1;";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof OCLInvalid);
		
		s="\'ab\'<\'abc\';";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof OCLInvalid);
	}
	
	public void testEqual() {
		Context context = new Context();
		context.registVariable("a", PrimitiveType.TYPE_INTEGER, false).setValue(new Integer(2));
		context.registVariable("b", PrimitiveType.TYPE_STRING, false).setValue("abc");
		context.registVariable("c", PrimitiveType.TYPE_BOOLEAN, false).setValue(new Boolean(false));
		context.registVariable("d", PrimitiveType.TYPE_INTEGER, false).setValue(OCLVoidValue.VOID);
		context.registVariable("e", PrimitiveType.TYPE_STRING, false).setValue(OCLVoidValue.VOID);
		QueryVisitor visitor = new ExpressionEnforceVisitor(context);
		Ast ast;
		String s;
		Object obj;
		s="2=2;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		
		s="true = true;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		
		s = "\'abc\'=\'abc\';";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		
		
		s="a=2;2=a;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		
		s="b=\'abc\';\'abc\'=b;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		
		s="d=2;d=3;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertFalse((Boolean)obj);
		Object result = context.getVariable("d");
		assertTrue(result instanceof Variable);
		assertTrue(((Variable)result).getValue() instanceof Integer);
		assertTrue(((Variable)result).getValue().equals(2));
		
		Variable d = context.getVariable("d");
		d.setValue(OCLVoidValue.VOID);
		s="a=d+1;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		assertTrue(d.getValue() instanceof Integer);
		assertTrue(d.getValue().equals(1));
		
		Variable e = context.getVariable("e");
		s="b='ab'+e;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		assertTrue(e.getValue() instanceof String);
		assertTrue(e.getValue().equals("c"));
		
		e = context.getVariable("e");
		e.setValue(OCLVoidValue.VOID);
		s="b='a'+e+'c';";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(obj == Boolean.TRUE);
		assertTrue(e.getValue() instanceof String);
		assertTrue(e.getValue().equals("b"));
	}
	
	public void testLogical() {
		Context context = new Context();
		context.registVariable("a", PrimitiveType.TYPE_INTEGER, false).setValue(new Integer(2));
		context.registVariable("b", PrimitiveType.TYPE_STRING, false).setValue("abc");
		context.registVariable("c", PrimitiveType.TYPE_BOOLEAN, false).setValue(new Boolean(false));
		QueryVisitor visitor = new ModelCheckVisitor(context);
		Ast ast;
		String s;
		Object obj;
		s="1<2 and true;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue((Boolean)obj);
		
		s="1>2 and true;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertFalse((Boolean)obj);
		
		s="1>2 or true;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue((Boolean)obj);
		
		s="not true;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertFalse((Boolean)obj);
	}
	
	public void testPlusMinus() {
		Context context = new Context();
		context.registVariable("a", PrimitiveType.TYPE_INTEGER, false).setValue(new Integer(2));
		context.registVariable("b", PrimitiveType.TYPE_STRING, false).setValue("abc");
		context.registVariable("c", PrimitiveType.TYPE_BOOLEAN, false).setValue(new Boolean(false));
		QueryVisitor visitor = new ModelCheckVisitor(context);
		Ast ast;
		String s;
		Object obj;
		s="a+3;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertTrue(obj.equals(5));
		
		s="b+'d';";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof String);
		assertTrue(obj.equals("abcd"));
		
		s="true+c;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof OCLInvalid);
				
		
		s="a+b;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof String);
		assertTrue(obj.equals("2abc"));
		
		s="a-2;";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertEquals(0, obj);
	}
	
	public void testLoop() {
		Variable a = new Variable();
		a.setType(PrimitiveType.TYPE_INTEGER);
		a.setValue(1);
		a.setName("a");
		Variable b = new Variable();
		b.setType(PrimitiveType.TYPE_INTEGER);
		b.setValue(2);
		b.setName("b");
		Variable c = new Variable();
		c.setType(PrimitiveType.TYPE_INTEGER);
		c.setValue(3);
		c.setName("c");

		ArrayList<Variable> l = new ArrayList<Variable>();
		l.add(a);
		l.add(b);
		l.add(c);
		ArrayList<Integer> l2 = new ArrayList<Integer>();
		l2.add(1);
		l2.add(2);
		Context context = new Context();
		context.registVariable("l", CollectionType.COLLECTION_BAG, false).setValue(l);
		context.registVariable("l2", CollectionType.COLLECTION_BAG, false).setValue(l2);
		QueryVisitor visitor = new ModelCheckVisitor(context);
		
		Ast ast;
		String s;
		Object obj;
		s="l->select(b:Integer | b>1);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof ArrayList);
		assertTrue(((ArrayList)obj).size() == 2);
		
		s="l2->collect(b:Integer | b+1);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof ArrayList);
		assertTrue(((ArrayList)obj).size() == 2);
		assertEquals(2, ((ArrayList)obj).get(0));
		assertEquals(3,	 ((ArrayList)obj).get(1));
		
		s="l2->forAll(b:Integer | b>1);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertFalse(((Boolean)obj));
		
		s="l2->forAll(b:Integer | b<4);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(((Boolean)obj));
		
		s="l2->exists(b:Integer | b>1);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertTrue(((Boolean)obj));
		
		s="l2->exists(b:Integer | b>4);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Boolean);
		assertFalse(((Boolean)obj));
	}
	
	public void testIf() {
		Context context = new Context();
		context.registVariable("a", PrimitiveType.TYPE_INTEGER, false).setValue(2);
		context.registVariable("b", PrimitiveType.TYPE_INTEGER, false).setValue(1);
		context.registVariable("c", PrimitiveType.TYPE_INTEGER, false).setValue(3);
		QueryVisitor visitor = new ModelCheckVisitor(context);
		
		Ast ast;
		String s;
		Object obj;
		s="if true then a;else b;endif";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertEquals(new Integer(2), (Integer)obj);
		
		
		s="if false then a;else b;endif";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertEquals(new Integer(1), (Integer)obj);
	}
	
	public void testFunction() {
		Context context = new Context();
		context.registVariable("a", PrimitiveType.TYPE_INTEGER, false).setValue(2);
		QueryVisitor visitor = new ModelCheckVisitor(context);
		Ast ast;
		String s;
		Object obj;
		s="query get():Integer{1;}";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		ast.accept(visitor);
		ast = ScriptParser.parse("get();");
		assertNotNull(ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertEquals(1, obj);
		
		s="query add(arg:Integer):Integer{arg+1;}";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		ast.accept(visitor);
		s="add(a);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertEquals(3, obj);
		
		s="query minus(arg:Integer):Integer{if arg<5 then minus(arg+1); else arg; endif}";
		ast = ScriptParser.parse(s);
		assertNotNull(ast);
		ast.accept(visitor);
		s="minus(a);";
		ast = ScriptParser.parse(s);
		assertNotNull("ast null", ast);
		obj = ast.accept(visitor);
		assertTrue(obj instanceof Integer);
		assertEquals(5, obj);
	}
	
	
	
}
